package com.zb.es;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Strings;
import com.zb.dto.DeviceDTO;
import com.zb.dto.DeviceLocation;
import com.zb.vo.Pager;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.common.geo.GeoDistance;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Repository
@Slf4j
public class EsRepository {

    @Autowired
    private RestHighLevelClient restHighLevelClient;


    /**
     * 根据设备GPS位置搜索
     *
     * @param lat
     * @param lon
     * @param distance
     * @return
     */
    public List<DeviceLocation> searchDevceLocation(Double lat, Double lon, Integer distance) {
        List<DeviceLocation> list = new ArrayList<>();

        SearchRequest searchRequest = new SearchRequest("gps");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //geo参数设置构建
        GeoDistanceQueryBuilder geoDistanceQueryBuilder = new GeoDistanceQueryBuilder("location");
        geoDistanceQueryBuilder.distance(distance, DistanceUnit.KILOMETERS);
        geoDistanceQueryBuilder.point(lat, lon);
        //构建查询
        searchSourceBuilder.query(geoDistanceQueryBuilder);
        //从近到远的规则构建
        GeoDistanceSortBuilder geoDistanceSortBuilder = new GeoDistanceSortBuilder("location", lat, lon);
        geoDistanceSortBuilder.unit(DistanceUnit.KILOMETERS);
        geoDistanceSortBuilder.order(SortOrder.ASC);
        geoDistanceSortBuilder.geoDistance(GeoDistance.ARC);//提高查询精准度
        searchSourceBuilder.sort(geoDistanceSortBuilder);
        //设置最大200条数据
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(200);
        searchRequest.source(searchSourceBuilder);
        //执行查询获取响应
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        SearchHits hits = searchResponse.getHits();

        if (hits.getTotalHits().value <= 0) {
            return list;
        }

        for (SearchHit hit : hits.getHits()) {
            DeviceLocation deviceLocation = new DeviceLocation();
            deviceLocation.setDeviceId(hit.getId());
            deviceLocation.setLocation(hit.getSourceAsMap().get("location").toString());
            list.add(deviceLocation);
        }

        return list;
    }


    /**
     * 添加设备的Gps位置
     *
     * @param deviceLocation
     */
    public void saveLocation(DeviceLocation deviceLocation) {
        IndexRequest indexRequest = new IndexRequest("gps");
        indexRequest.source("location", deviceLocation.getLocation());
        indexRequest.id(deviceLocation.getDeviceId());
        try {
            IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
            System.out.println(indexResponse.status());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 全部设备总数
     *
     * @return
     */
    public Long getAllDeviceCount() {
        CountRequest countRequest = new CountRequest("device");
        countRequest.query(QueryBuilders.matchAllQuery());
        try {
            CountResponse countResponse = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
            return countResponse.getCount();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 离线设备总数
     *
     * @return
     */
    public Long getOffLineCount() {
        CountRequest countRequest = new CountRequest("device");
        countRequest.query(QueryBuilders.termQuery("online", false));
        try {
            CountResponse countResponse = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
            return countResponse.getCount();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 报警设备总数
     *
     * @return
     */
    public Long getAlarmCount() {
        CountRequest countRequest = new CountRequest("device");
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termQuery("online", true));
        boolQueryBuilder.must(QueryBuilders.termQuery("alarm", true));
        countRequest.query(boolQueryBuilder);
        try {
            CountResponse countResponse = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
            return countResponse.getCount();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    public Pager<DeviceDTO> searchDevice(Long page, Long pageSize, String deviceId, String tag, Integer status) {
        SearchRequest searchRequest = new SearchRequest("device");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (!Strings.isNullOrEmpty(deviceId)) {
            boolQueryBuilder.must(QueryBuilders.wildcardQuery("deviceId", deviceId + "*"));
        }
        if (!Strings.isNullOrEmpty(tag)) {
            boolQueryBuilder.must(QueryBuilders.wildcardQuery("tag", "*" + tag + "*"));
        }
        //在线（0）、离线（1）、一般告警（2）、严重告警（3）
        if (status != null) {
            if (status.intValue() == 0) {
                boolQueryBuilder.must(QueryBuilders.termQuery("online", true));
            }
            if (status.intValue() == 1) {
                boolQueryBuilder.must(QueryBuilders.termQuery("online", false));
            }
            if (status.intValue() == 2) {
                boolQueryBuilder.must(QueryBuilders.termQuery("level", 1));
            }
            if (status.intValue() == 3) {
                boolQueryBuilder.must(QueryBuilders.termQuery("level", 2));
            }
        }
        searchSourceBuilder.query(boolQueryBuilder);
        searchSourceBuilder.from((page.intValue() - 1) * pageSize.intValue());
        searchSourceBuilder.size(pageSize.intValue());

        //添加排序
        searchSourceBuilder.sort("level", SortOrder.DESC);
        searchRequest.source(searchSourceBuilder);
        //执行获取响应
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits hits = searchResponse.getHits();
            SearchHit[] searchHits = hits.getHits();
            List<DeviceDTO> devices = new ArrayList<>();
            for (SearchHit hit : searchHits) {
                String hitResult = hit.getSourceAsString();
                DeviceDTO deviceDTO = JSON.parseObject(hitResult, DeviceDTO.class);
                devices.add(deviceDTO);
            }
            Pager<DeviceDTO> pager = new Pager<>(hits.getTotalHits().value, pageSize);
            pager.setItems(devices);
            return pager;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 更新设备的状态
     *
     * @param deviceId
     * @param online
     */
    public boolean updateOnline(String deviceId, Boolean online) {
        UpdateRequest updateRequest = new UpdateRequest("device", deviceId);
        updateRequest.doc("online", online);
        try {
            restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 更新报警信息
     */
    public boolean updateDeviceAlarm(DeviceDTO deviceDTO) {
        UpdateRequest updateRequest = new UpdateRequest("device", deviceDTO.getDeviceId());
        updateRequest.doc("alarm", deviceDTO.getAlarm(),
                "alarmName", deviceDTO.getAlarmName(),
                "level", deviceDTO.getLevel());
        try {
            restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 更新设备的状态
     *
     * @param deviceId
     * @param tag
     */
    public boolean updateDeviceTag(String deviceId, String tag) {
        UpdateRequest updateRequest = new UpdateRequest("device", deviceId);
        updateRequest.doc("tag", tag);
        try {
            restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 更新设备的状态
     *
     * @param deviceId
     * @param status
     */
    public boolean updateStatus(String deviceId, Boolean status) {
        UpdateRequest updateRequest = new UpdateRequest("device", deviceId);
        updateRequest.doc("status", status);
        try {
            restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /*
    添加设备
     */
    public void addDevice(DeviceDTO deviceDTO) {
        if (deviceDTO == null) return;
        IndexRequest indexRequest = new IndexRequest("device");
        String json = JSON.toJSONString(deviceDTO);
        Map map = JSON.parseObject(json, Map.class);
        indexRequest.source(map);
        indexRequest.id(deviceDTO.getDeviceId());
        try {
            IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
            log.info("添加设备成功！" + response.status().name());
        } catch (IOException e) {
            e.printStackTrace();
            log.error("设备添加发送异常");
        }


    }

    /**
     * 根据编号查询设备
     *
     * @param deviceId
     * @return
     */
    public DeviceDTO searchDeviceById(String deviceId) {
        SearchRequest searchRequest = new SearchRequest("device");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.termQuery("_id", deviceId));
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            long count = searchResponse.getHits().getTotalHits().value;
            if (count <= 0) return null;
            DeviceDTO deviceDTO = null;
            for (SearchHit hit : searchResponse.getHits()) {
                String hitResult = hit.getSourceAsString();
                deviceDTO = JSON.parseObject(hitResult, DeviceDTO.class);
                break;
            }
            return deviceDTO;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }


}
